package com.example.springboot.service.impl;


import com.alibaba.fastjson.JSON;
import com.example.springboot.service.ProductScoreService;
import com.example.springboot.utils.RecommendFactory;
import org.apache.mahout.cf.taste.common.TasteException;
import org.apache.mahout.cf.taste.impl.neighborhood.NearestNUserNeighborhood;
import org.apache.mahout.cf.taste.impl.recommender.CachingRecommender;
import org.apache.mahout.cf.taste.impl.recommender.GenericUserBasedRecommender;
import org.apache.mahout.cf.taste.impl.similarity.PearsonCorrelationSimilarity;
import org.apache.mahout.cf.taste.model.DataModel;
import org.apache.mahout.cf.taste.neighborhood.UserNeighborhood;
import org.apache.mahout.cf.taste.recommender.RecommendedItem;
import org.apache.mahout.cf.taste.recommender.Recommender;
import org.apache.mahout.cf.taste.similarity.ItemSimilarity;
import org.apache.mahout.cf.taste.similarity.UserSimilarity;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * (ProductScore)表服务实现类
 *
 * @author makejava
 * @since 2024-03-30 15:18:44
 */
@Service("productScoreService")
public class ProductScoreServiceImpl implements ProductScoreService {
    @Autowired
    private ProductScoreMapper productScoreMapper;
    @Autowired
    private ProductMapper productMapper;

    /**
     * 获取用户喜好
     */
    public List<Product> recommend(Long userId, Integer size) throws TasteException {
        List<ProductScore> list = productScoreMapper.listAllCustomerPreference();
        //创建模型数据
        DataModel dataModel = RecommendFactory.buildJdbcDataModel(list);
        //2list = {ArrayList@8644}  size = 93.创建similar相似度
        UserSimilarity similarity = new PearsonCorrelationSimilarity(dataModel);
        double similarity2 = similarity.userSimilarity(40L, 39L);

        //3.获取用户userNeighborhood
        UserNeighborhood userNeighborhood = new NearestNUserNeighborhood(5, similarity, dataModel);
        long[] neighborhood = userNeighborhood.getUserNeighborhood(userId);  // 存储邻居的ID
        System.out.println("当前用户的邻居：" + JSON.toJSONString(neighborhood));
        //4.构建推荐器recommend
//        Recommender recommender = new GenericUserBasedRecommender(dataModel, userNeighborhood, similarity);
        CachingRecommender recommender = new CachingRecommender(new GenericUserBasedRecommender(dataModel, userNeighborhood, similarity));

//        IDRescorer rescorer = new FilterRescorer(list.stream().map(ProductScore::getUserId).collect(Collectors.toSet()));

        //展示类似的5个商品
//        List<RecommendedItem> recommendedItems = recommender.recommend(userId, size, rescorer);
        List<RecommendedItem> recommendedItems = recommender.recommend(userId, size);

        List<Long> productIds = recommendedItems.stream().map(RecommendedItem::getItemID).collect(Collectors.toList());
        List<Product> products = new ArrayList<>();
        for (Long productId : productIds) {
            Product product = productMapper.selectById(Integer.parseInt(String.valueOf(productId)));
            products.add(product);
        }
        return products;

    }

    /**
     * 获取商品喜好
     */
    public List<Long> recommendItem(Long itemId) throws TasteException {
        List<ProductScore> list = productScoreMapper.listAllCustomerPreference();
        //创建模型数据
        DataModel dataModel = RecommendFactory.buildJdbcDataModel(list);
        //2.创建similar相似度
        ItemSimilarity similarity = RecommendFactory.itemSimilarity(RecommendFactory.SIMILARITY.PEARSON, dataModel);

        //4.构建推荐器recommend
        Recommender recommender = RecommendFactory
                .itemRecommender(similarity, true)
                .buildRecommender(dataModel);

        //展示类似的5个商品
        List<RecommendedItem> recommendedItems = recommender.recommend(itemId, 5);
        return recommendedItems.stream().map(RecommendedItem::getItemID).collect(Collectors.toList());
    }

    public ProductScore select(ProductScore productScore) {
        try {
            return productScoreMapper.select(productScore);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    public void update(ProductScore productScore) {
        try {
            productScoreMapper.update(productScore);
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException("更新失败");
        }
    }

    public void insert(ProductScore productScore) {
        try {
            productScoreMapper.insert(productScore);
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException("插入失败");
        }
    }
}
